#include "CHIP_UART_module/CHIP_UART.hpp"

//#define CHIP_UART_DEBUG

#ifdef DBG_TAG
#undef DBG_TAG
#endif
#ifdef DBG_LVL
#undef DBG_LVL
#endif

#define DBG_TAG     "chip_uart"
#define DBG_LVL     DBG_LOG

extern "C"
{
#include <rtdbg.h>
}
using namespace std;

chip_uart_message::chip_uart_message()
{
    message = NULL;
    message_length = 0;
    now_end_pos = 0;
}

chip_uart_message::chip_uart_message(uint32_t length)
{
    if (length <= 0)
    {
        LOG_E("cant create with length <=0");
        goto end;
    }
    message = (uint8_t*) rt_malloc(length);
    if (!message)
    {
        LOG_E("no mem for uart message in create");
        goto end;
    }
    rt_memset(message, 0, length);
    message_length = length;
    now_end_pos = 0;
    return;
    end: now_end_pos = 0;
    message_length = 0;

}

chip_uart_message::chip_uart_message(const chip_uart_message &ob)
{
    if (!message)
    {
        message = (uint8_t*) rt_malloc(ob.message_length);
        if (!message)
        {
            LOG_E("no mem for uart message in copy");
            goto end;
        }
    }
    else
    {
        message = (uint8_t*) rt_realloc(message, ob.message_length);
        if (!message)
        {
            LOG_E("no mem for uart message in copy");
            goto end;
        }
    }
    memcpy(message, ob.message, ob.message_length);
    message_length = ob.message_length;
    now_end_pos = ob.now_end_pos;
    return;
    end: message_length = 0;
    now_end_pos = 0;
}

chip_uart_message::~chip_uart_message()
{
    if (message)
    {
        rt_free(message);
        message = NULL;
    }
}

chip_uart_status chip_uart_message::add_uin8_t(uint8_t add_data)
{
    uint8_t * new_message;
    if (now_end_pos + 1 < message_length)
    {
        message[now_end_pos] = add_data;
        now_end_pos++;
    }
    else
    {
        new_message = (uint8_t*) rt_realloc(message, message_length + 64);
        if (!new_message)
        {
            LOG_E("no mem for uart message in add one");
            goto end;
        }
        message = new_message;
        rt_memset(message + message_length, 0, 64);
        message[now_end_pos] = add_data;
        now_end_pos++;
        message_length += 64;
    }

    return chip_uart_status_ok;
    end: return chip_uart_status_fail;

}

chip_uart_status chip_uart_message::add_uin8_t_array(uint8_t* add_data_buff, uint32_t length)
{
    uint8_t * new_message;
    uint32_t extend_length = 0;
    if (now_end_pos + length < message_length)
    {
        rt_memcpy(message + now_end_pos, add_data_buff, length);
        now_end_pos += length;
    }
    else
    {
        extend_length = now_end_pos + length - message_length + 1;
        new_message = (uint8_t*) rt_realloc(message, message_length + extend_length);
        if (!new_message)
        {
            LOG_E("no mem for uart message add array");
            goto end;
        }
        message = new_message;
        rt_memset(message + message_length, 0, extend_length);
        rt_memcpy(message + now_end_pos, add_data_buff, length);
        now_end_pos += length;
        message_length += extend_length;
    }

    return chip_uart_status_ok;
    end: return chip_uart_status_fail;

}

chip_uart_status chip_uart_message::apply_more_mem_for_msg(uint32_t add_length)
{
    uint8_t * new_message;

    new_message = (uint8_t*) rt_realloc(message, message_length + add_length);
    if (!new_message)
    {
        LOG_E("no mem for uart message apply mem");
        goto end;
    }
    message = new_message;
    rt_memset(message + message_length, 0, add_length);
    message_length += add_length;

    return chip_uart_status_ok;
    end: return chip_uart_status_fail;
}

CHIP_UART::CHIP_UART(std::string uart_name, struct serial_configure* serial_config)
{

    string name;
    struct serial_configure control = RT_SERIAL_CONFIG_DEFAULT;
    max_recv_size = 10240;//10KB
    used_recv_size = 0;
    if (uart_name.empty())
    {
        LOG_E("uart create fail : uart dev name is NULL");
        goto end;
    }
    serial_sem = RT_NULL;
    read_lock = RT_NULL;

    serial = rt_device_find(uart_name.c_str());
    if (!serial)
    {
        LOG_E("uart create fail : uart dev <%s> must be set in board.h before use", uart_name.c_str());
        goto end;
    }
    this->uart_name = uart_name;

    //如果使用空配置则配置串口为默认
    if (!serial_config)
        LOG_W("uart create: serial_config is NULL,use default config");
    else
    {

        control.baud_rate = serial_config->baud_rate;
        control.data_bits = serial_config->data_bits;
        control.stop_bits = serial_config->stop_bits;
        control.parity = serial_config->parity;
        control.invert = serial_config->invert;
        control.bufsz = serial_config->bufsz;
        control.bit_order = serial_config->bit_order;
    }
    this->serial_config = control;

    if (rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &control) != RT_EOK)
    {
        LOG_E("uart create fail : uart dev <%s> setting para fail", uart_name.c_str());
        goto end;
    }

    if (rt_device_open(serial, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
    {
        LOG_E("uart create fail : uart dev <%s> open fail", uart_name.c_str());
        goto end;
    }

    //创建回调中使用到的信号量
    name = uart_name;
    name += "_sem";
    serial_sem = rt_sem_create(name.c_str(), 0, RT_IPC_FLAG_FIFO);
    if (serial_sem == RT_NULL)
    {
        LOG_E("uart create fail : uart sem <%s> create fail", name.c_str());
        goto end;
    }

    name = uart_name;
    name += "_rsem";
    read_sem = rt_sem_create(name.c_str(), 0, RT_IPC_FLAG_FIFO);
    if (read_sem == RT_NULL)
    {
        LOG_E("uart create fail : uart read_sem <%s> create fail", name.c_str());
        goto end;
    }


    //创建读取线程锁
    name = uart_name;
    name += "_lock";
    read_lock = rt_mutex_create(name.c_str(), RT_IPC_FLAG_FIFO);
    if (read_lock == RT_NULL)
    {
        LOG_E("uart create fail : uart lock <%s> create fail", name.c_str());
        goto end;
    }

#ifdef CHIP_UART_DEBUG
//    LOG_D("serial<%X> serial_temp<%X>",serial,serial_temp);

    CHIP_UART_send(rt_strlen("serial is working\r\n"),"serial is working\r\n");
//    rt_device_write(serial, 0, "serial is working\r\n", rt_strlen("serial is working\r\n"));

#endif

    LOG_I("uart <%s> create ok", uart_name.c_str());
    init_flag = chip_uart_status_ok;
    return;
    end:
    LOG_E("uart <%s> create fail", uart_name.c_str());
    if (serial_sem)
        rt_sem_delete(serial_sem);
    if (read_lock)
        rt_mutex_delete(read_lock);
    init_flag = chip_uart_status_fail;
}

CHIP_UART::CHIP_UART(std::string uart_name, struct serial_configure* serial_config, chip_uart_mode mode)
{
    string name;
    struct serial_configure control = RT_SERIAL_CONFIG_DEFAULT;

    max_recv_size = 10240;//10KB
    used_recv_size = 0;

    if (uart_name.empty())
    {
        LOG_E("uart create fail : uart dev name is NULL");
        goto end;
    }
    serial_sem = RT_NULL;
    read_lock = RT_NULL;

    serial = rt_device_find(uart_name.c_str());
    if (!serial)
    {
        LOG_E("uart create fail : uart dev <%s> must be set in board.h before use", uart_name.c_str());
        goto end;
    }
    this->uart_name = uart_name;

    //如果使用空配置则配置串口为默认
    if (!serial_config)
        LOG_W("uart create: serial_config is NULL,use default config");
    else
    {

        control.baud_rate = serial_config->baud_rate;
        control.data_bits = serial_config->data_bits;
        control.stop_bits = serial_config->stop_bits;
        control.parity = serial_config->parity;
        control.invert = serial_config->invert;
        control.bufsz = serial_config->bufsz;
        control.bit_order = serial_config->bit_order;
    }
    this->serial_config = control;

    if (rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &control) != RT_EOK)
    {
        LOG_E("uart create fail : uart dev <%s> setting para fail", uart_name.c_str());
        goto end;
    }
    switch (mode)
    {
    case chip_uart_mode_int:
        if (rt_device_open(serial, RT_DEVICE_FLAG_INT_RX) != RT_EOK)
        {
            LOG_E("uart create fail : uart dev <%s> open fail", uart_name.c_str());
            goto end;
        }
        break;
    case chip_uart_mode_dma:
        if (rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX) != RT_EOK)
        {
            LOG_E("uart create fail : uart dev <%s> open fail", uart_name.c_str());
            goto end;
        }
        break;
    default:
        LOG_E("uart create: invalid mode");
        goto end;
        break;
    }

    //创建回调中使用到的信号量
    name = uart_name;
    name += "_sem";
    serial_sem = rt_sem_create(name.c_str(), 0, RT_IPC_FLAG_FIFO);
    if (serial_sem == RT_NULL)
    {
        LOG_E("uart create fail : uart sem <%s> create fail", name.c_str());
        goto end;
    }

    name = uart_name;
    name += "_rsem";
    read_sem = rt_sem_create(name.c_str(), 0, RT_IPC_FLAG_FIFO);
    if (read_sem == RT_NULL)
    {
        LOG_E("uart create fail : uart read_sem <%s> create fail", name.c_str());
        goto end;
    }

    //创建读取线程锁
    name = uart_name;
    name += "_lock";
    read_lock = rt_mutex_create(name.c_str(), RT_IPC_FLAG_FIFO);
    if (read_lock == RT_NULL)
    {
        LOG_E("uart create fail : uart lock <%s> create fail", name.c_str());
        goto end;
    }

#ifdef CHIP_UART_DEBUG
//    LOG_D("serial<%X> serial_temp<%X>",serial,serial_temp);

    CHIP_UART_send(rt_strlen("serial is working\r\n"),"serial is working\r\n");
//    rt_device_write(serial, 0, "serial is working\r\n", rt_strlen("serial is working\r\n"));

#endif

    LOG_I("uart <%s> create ok", uart_name.c_str());
    init_flag = chip_uart_status_ok;
    return;
    end:
    LOG_E("uart <%s> create fail", uart_name.c_str());
    if (serial_sem)
        rt_sem_delete(serial_sem);
    if (read_lock)
        rt_mutex_delete(read_lock);
    init_flag = chip_uart_status_fail;
}

CHIP_UART::~CHIP_UART()
{
    chip_uart_message * temp;
    if (serial_sem)
        rt_sem_delete(serial_sem);
    if (read_lock)
        rt_mutex_delete(read_lock);
    while (!receive_list.empty())
    {
        temp = receive_list.front();
        receive_list.erase(receive_list.begin());
        delete temp;
    }
    receive_list.swap(receive_list);
}

//rxfunc 中调用本实体中的sem
chip_uart_status CHIP_UART::CHIP_UART_init_rx_interrupt(rt_err_t (*rxfunc)(rt_device_t dev, rt_size_t size))
{
    /* 设置接收回调函数 */
    if (rt_device_set_rx_indicate(serial, rxfunc) != RT_EOK)
    {
        LOG_E(" dev <%s> rx callback function create fail", uart_name.c_str());
        return chip_uart_status_fail;
    }
    else
    {
        LOG_I(" dev <%s> rx callback function create ok", uart_name.c_str());
        return chip_uart_status_ok;

    }
}

void CHIP_UART::CHIP_UART_rx_default_callback()
{
    rt_sem_release(serial_sem);
}

void CHIP_UART::CHIP_UART_rx_default_thread_handler()
{
    uint32_t read_length;
    chip_uart_status msg_flag ;
    chip_uart_message* message = nullptr;
    rt_tick_t start,end;
    while (1)
    {

        rt_sem_take(serial_sem, RT_WAITING_FOREVER);
        rt_sem_control(serial_sem, RT_IPC_CMD_RESET, 0);
#ifdef CHIP_UART_DEBUG
        start = rt_tick_get();
#endif
        if(used_recv_size + 128 > max_recv_size)
            message = nullptr;
        else
        {
            message = new chip_uart_message(128);
            used_recv_size += 128;
        }

        if (!message)
        {
            LOG_E("no mem for rx message");
            continue;
        }
        do
        {
            msg_flag = chip_uart_status_ok;
            do
            {
                read_length = rt_device_read(serial, -1, (message->message) + (message->now_end_pos), 128);
                message->now_end_pos += read_length;
                if (message->now_end_pos + 128 >= message->message_length)
                {
                    if(used_recv_size + 128 > max_recv_size)
                    {
                        LOG_E("no mem for uart message apply mem");
                        msg_flag = chip_uart_status_fail;
                    }
                    else
                    {
                        msg_flag = message->apply_more_mem_for_msg(128);
                        used_recv_size += 128;
                    }

                }
            } while (read_length && msg_flag == chip_uart_status_ok);

            if(msg_flag != chip_uart_status_ok)
                break;
        } while (rt_sem_take(serial_sem, 20) == RT_EOK); //该处可以调节超时时间以分别两个消息

        if(msg_flag == chip_uart_status_ok)
        {
            rt_mutex_take(read_lock, RT_WAITING_FOREVER);
            receive_list.push_back(message);
            rt_mutex_release(read_lock);
        }
        else {

            delete message;
            message = nullptr;
        }


        rt_sem_release(read_sem);

#ifdef CHIP_UART_DEBUG

        end = rt_tick_get();
        LOG_D("recv thread time <%u>",end-start);

        //回显测试
        LOG_D("push back");
        message = CHIP_UART_read_receive(100);
        if(message)
        {
            LOG_D("recevied: %s",message->message);
        }
        delete message;
#endif

    }
}

chip_uart_status CHIP_UART::CHIP_UART_send(uint32_t send_len, const void * send_buff)
{
#ifdef CHIP_UART_DEBUG
    int i;
    for(i = 0;i<send_len;i++)
    {
        LOG_D("send <%d> <0x%.2X>",i,((uint8_t*)send_buff)[i]);
    }
#endif
    if (rt_device_write(serial, 0, send_buff, send_len) == 0)
    {
        LOG_E("send error");
        return chip_uart_status_fail;
    }
    else
        return chip_uart_status_ok;
}

//返回时使用完delete
chip_uart_message* CHIP_UART::CHIP_UART_read_receive(uint32_t timeout)
{
    uint8_t i = 2;
    chip_uart_message* message_back = nullptr;

    rt_sem_take(read_sem, timeout);

    if (receive_list.empty())
        goto end;
    rt_mutex_take(read_lock, RT_WAITING_FOREVER);
    message_back = receive_list.front();
    receive_list.erase(receive_list.begin());
    if (receive_list.capacity() > 1000)
        receive_list.swap(receive_list);
    rt_mutex_release(read_lock);

    used_recv_size -= message_back->message_length;
    end:
    return message_back;
}

chip_uart_status CHIP_UART::CHIP_UART_read_init_status()
{
    return init_flag;
}
